﻿using System.Collections.Generic;
using IQIGame.Onigao.Game;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class EffectComponent : TComponent
    {
        private UnitView unit;
        private Dictionary<uint, Effect> mEffect = new Dictionary<uint, Effect>();
        private Dictionary<uint, EffectInitParam> add = new Dictionary<uint, EffectInitParam>();
        private List<uint> remove = new List<uint>();

        public override void OnUpdate(float deltaTime)
        {
            base.OnUpdate(deltaTime);

            for (int i = 0; i < this.remove.Count; i++)
            {
                var nRemoveId = this.remove[i];
                if (this.add.ContainsKey(nRemoveId))
                {
                    this.add.Remove(nRemoveId);
                }
                if (this.mEffect.TryGetValue(nRemoveId, out var rEffect))
                {
                    BattleEffectManager.Instance.Stop(rEffect);
                    this.mEffect.Remove(nRemoveId);
                }
            }
            this.remove.Clear();
            foreach (var rPair in this.add)
            {
                this.PlayEffect(rPair.Key, rPair.Value);
            }
            this.add.Clear();
        }

        protected override void OnDispose()
        {
            this.add.Clear();
            this.remove.Clear();
            foreach (var rPair in this.mEffect)
            {
                BattleEffectManager.Instance.Stop(rPair.Value);
            }

            this.mEffect.Clear();
        }

        public override void OnCreate(TEntity entity)
        {
            this.unit = entity as UnitView;
        }

        public uint AddBuffEffect(string rEffectPath, int nDummyID, EVFXSpace rSpace, bool isLoop)
        {
            var rBind = this.unit.GetComponent<BattleViewBindPointComponent>(ETComponentType.BattleViewBindPointComponent);
            if (rBind != null)
            {
                var rDummyTrans = rBind.GetBindPoint(nDummyID);
                var rInitParam = new EffectInitParam(PathConstant.GetBuffEffectPath(rEffectPath), rDummyTrans, Vector3.zero, Quaternion.identity, isLoop: isLoop, vfxSpace: rSpace);
                return this.AddEffect(rInitParam);
            }

            return 0;
        }

        public uint AddTimelineEffect(string effectName, Vector3 worldPos, bool isLoop)
        {
            if (!string.IsNullOrEmpty(effectName))
            {
                var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
                var rEffectPath = this.GetRoleEffectPath(effectName);
                // 在这里播放世界坐标的特效
                var rInitParam = new EffectInitParam(rEffectPath, rViewComp.transform, worldPos, rViewComp.rotation,
                    null, 1f, isLoop, EVFXSpace.World);
                return this.AddEffect(rInitParam);
            }
            return 0;
        }

        public uint AddTimelineEffect(string effectName, int dummyID, EVFXSpace space, bool isLoop, float defauleLength, Vector3 shifting)
        {
            if (!string.IsNullOrEmpty(effectName))
            {
                var rPath = this.GetRoleEffectPath(effectName);
                return this.AddTimelineEffectWithPath(rPath, dummyID, space, isLoop, defauleLength, true, null, shifting);
            }
            return 0;
        }

        public uint AddTimelineEffectWithPath(string effectPath, int dummyID, EVFXSpace space, bool isLoop, float defauleLength, bool byTimelineTrack, BattleViewBindPointComponent targetBindComp, Vector3 shifting)
        {
            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            Transform rDummyTrans = null;
            if (rViewComp != null)
            {
                var rBind = this.unit.GetComponent<BattleViewBindPointComponent>(ETComponentType.BattleViewBindPointComponent);
                rDummyTrans = rBind.GetBindPoint(dummyID);
                var rTargetPos = rViewComp.position;
                if (defauleLength > 0)
                {
                    var rForward = rViewComp.forward;
                    rTargetPos = rViewComp.position + rForward * defauleLength;
                }

                var rInitParam = new EffectInitParam(effectPath, rDummyTrans, shifting, Quaternion.identity, rTargetPos, targetBindComp,
                    1, isLoop, space, null, !byTimelineTrack);
                return this.AddEffect(rInitParam);
            }

            return 0;
        }

        public uint AddBulletEffect(string rEffectName, Vector3 rStartPos, Quaternion rStartRot)
        {
            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            if (rViewComp != null && !string.IsNullOrEmpty(rEffectName))
            {
                var rInitParam = new EffectInitParam(this.GetRoleEffectPath(rEffectName), null, rStartPos, rStartRot,
                    isLoop: true, vfxSpace: EVFXSpace.WorldPosition);
                return this.AddEffect(rInitParam);
            }
            return 0;
        }

        public uint AddHitEffect(string rHitEffectPath)
        {
            int nHitDummy = 2;

            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            if (rViewComp != null)
            {
                var rBind = this.unit.GetComponent<BattleViewBindPointComponent>(ETComponentType.BattleViewBindPointComponent);
                var rDummyTrans = rBind.GetBindPoint(nHitDummy);

                if (!string.IsNullOrEmpty(rHitEffectPath))
                {
                    var rInitParam = new EffectInitParam(rHitEffectPath, rDummyTrans, Vector3.zero, Quaternion.identity, vfxSpace: EVFXSpace.Local);
                    return this.AddEffect(rInitParam);
                }
            }

            return 0;
        }

        public uint AddEffect(EffectInitParam rInitParam)
        {
            var nID = Effect.GetInstId();
            this.add.TryAdd(nID, rInitParam);
            return nID;
        }

        public string GetRoleEffectPath(string rEffectName)
        {
            var rViewComp = this.unit.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            if (rViewComp == null && this.unit is TotemView rTotem)
            {
                rViewComp = rTotem.summoner.GetComponent<UnitViewComponent>(ETComponentType.UnitViewComponent);
            }
            var rCurRes = rViewComp.curRes;
            return rCurRes.entityType == 0
                ? EffectReuseGlobal.GetHeroEffectPath(rCurRes.resName, rEffectName)
                : EffectReuseGlobal.GetMonsterEffectPath(rCurRes.resName, rEffectName);
        }

        public string GetHitEffectBySkill(EDamageType rType, int nSkillID)
        {
            string rPath = string.Empty;
            if (nSkillID > 0)
            {
                var rTabConfig = TableCenter.skill.Get(nSkillID);
                if (!string.IsNullOrEmpty(rTabConfig?.HitEffect))
                {
                    rPath = this.GetRoleEffectPath(rTabConfig.HitEffect);
                }
            }
            if (string.IsNullOrEmpty(rPath))
            {
                rPath = PathConstant.GetBattleHitEffectPath(BattleClientUtil.GetHitEffectNameByDamageType(rType));
            }
            return rPath;
        }

        public void RemoveEffect(uint uid)
        {
            this.remove.Add(uid);
        }

        private void PlayEffect(uint uid, EffectInitParam rParam)
        {
            var rEffect = BattleEffectManager.Instance.PlayEffect(rParam, uid);
            if (rParam.isLoop)
            {
                this.mEffect.TryAdd(uid, rEffect);
            }
        }
    }
}